package com.sunseagear.common.utils;


import cn.hutool.core.io.FileUtil;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * 文件操作类
 *
 * @author Administrator
 */
@Slf4j
public class FileUtils extends FileUtil {

    private static final String[] IMAGES_SUFFIXES = {"bmp", "jpg", "jpeg", "gif", "png", "tiff"};

    public static boolean isAbsolutePath(String path) {
        return path.startsWith("/") || path.contains(":");
    }

    // 创建单个文件
    public static File createFile(String filePath) {
        return touch(filePath);
    }

    /**
     * 在指定的位置创建文件夹
     *
     * @param dirPath 文件夹路径
     * @return 若创建成功，则返回True；反之，则返回False
     */
    public static File createDir(String dirPath) {
        return mkdir(dirPath);
    }

    /**
     * 删除指定的文件
     *
     * @param path 文件路径
     * @return 若删除成功，则返回True；反之，则返回False
     */
    public static boolean delFileOrDir(String path) {
        return del(path);
    }

    /**
     * 移动指定的文件（夹）到目标文件（夹）
     *
     * @param source     源文件（夹）
     * @param target     目标文件（夹）
     * @param isOverride 是否覆盖，则为True；反之为False
     */
    public static boolean move(String source, String target, boolean isOverride) {
        copy(source, target, isOverride);
        return delFileOrDir(source);
    }

    /**
     * 将文件转字节数组
     */
    public static byte[] readBytes(String filePath) {
        return FileUtil.readBytes(new File(filePath));
    }

    /**
     * 根据byte数组，生成文件
     */
    public static void saveFile(byte[] bfile, String filePath) {
        try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(Objects.requireNonNull(createFile(filePath))))) {
            bos.write(bfile);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("文件写入失败");
        }
    }

    public static List<File> readDirFilesFilter(String filePath, String filterName) {
        List<File> fs = readDirFiles(filePath);
        List<File> rs = new ArrayList<>();
        for (File file : fs) {
            String fName = file.getName();
            if (!fName.isEmpty() && fName.toLowerCase().endsWith(filterName.toLowerCase())) {
                rs.add(file);
            }
        }

        return rs;
    }

    public static List<File> readDirFiles(String filepath) {
        return Arrays.stream(ls(filepath)).toList();
    }

    public static void zipFile(String srcFileName, String zipFileName) {
        try {
            ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFileName)));
            zipFile(out, new File(srcFileName), "");
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void zipFile(ZipOutputStream out, File file, String base) throws IOException {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            base = base + "/";
            for (File tmpFile : Objects.requireNonNull(files)) {
                zipFile(out, tmpFile, base + tmpFile.getName());
            }
        } else {
            try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file), 10240)) {
                out.putNextEntry(new ZipEntry(base));

                byte[] buf = new byte[10240];
                int read;
                while ((read = bis.read(buf, 0, 10240)) != -1) {
                    out.write(buf, 0, read);
                }
            }
            out.closeEntry();
        }
    }

    public void unZipFile(String unZipBeforeFile, String unZipAfterFile) {
        try {
            try (ZipInputStream zis = new ZipInputStream(new FileInputStream(unZipBeforeFile))) {
                File f = new File(unZipAfterFile);
                f.mkdirs();
                unZipFile(zis, f);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void unZipFile(ZipInputStream zis, File file) throws Exception {
        ZipEntry zip;
        while ((zip = zis.getNextEntry()) != null) {
            String name = zip.getName();
            File f = new File(file.getAbsolutePath() + "/" + name);

            if (zip.isDirectory()) {
                f.mkdirs();
            } else {
                f.createNewFile();
                try (FileOutputStream fos = new FileOutputStream(f)) {
                    byte[] b = new byte[10240];
                    int aa;
                    while ((aa = zis.read(b)) != -1) {
                        fos.write(b, 0, aa);
                    }
                }
            }
            unZipFile(zis, file);
        }
    }

    public static byte[] getFileContent(String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            return new byte[0];
        }

        try (InputStream fr = new FileInputStream(file)) {
            byte[] content = new byte[(int) file.length()];

            int length = fr.read(content);
            if (length == file.length()) {
                return content;
            } else {
                log.info("File: " + filePath + " getFileContent error. Only read " + length + " bytes out of " + file.length());
                return new byte[0];
            }
        } catch (IOException e) {
            log.info("File: " + filePath + " getFileContent error", e);
        }

        return new byte[0];
    }


    /**
     * 将某个服务器上的文件提供下载服务
     * @param response
     * @param filePath
     * @param fileName
     * @throws Exception
     */
    public static void fileDownload(HttpServletResponse response, String filePath, String fileName) throws Exception {
        byte[] data = readBytes(filePath);
        fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
        response.reset();
        response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
        response.addHeader("Content-Length", "" + data.length);

        response.setContentType("application/x-download");
        OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
        outputStream.write(data);
        outputStream.flush();
        outputStream.close();
        response.flushBuffer();
    }

    public static void safeCloseReader(Reader reader) {
        if (null != reader) {
            try {
                reader.close();
            } catch (IOException e) {
                log.error("close file error:" + e.getMessage(), e);
            }
        }
    }

    public static void safeCloseOutputStream(OutputStream out) {
        if (null != out) {
            try {
                out.close();
            } catch (IOException e) {
                log.error("close file error:" + e.getMessage(), e);
            }
        }
    }

    public static void safeCloseInputStream(InputStream in) {
        if (null != in) {
            try {
                in.close();
            } catch (IOException e) {
                log.error("close file error:" + e.getMessage(), e);
            }
        }
    }

    public static void safeFlushAndCloseOutputStream(OutputStream out) {
        if (null != out) {
            try {
                out.flush();
            } catch (IOException e) {
                log.error("close file error:" + e.getMessage(), e);
            } finally {
                try {
                    out.close();
                } catch (IOException e) {
                    log.error("close file error:" + e.getMessage(), e);
                }
            }
        }
    }

    public static String getFileType(String url) {
        if (url == null || url.trim().isEmpty()) {
            return null;
        }
        int pos = url.lastIndexOf(".") + 1;
        return url.substring(pos);
    }

    //BASE64解码成File文件
    public static boolean base64ToFile(String destPath, String base64, String fileName) {
        File dir = new File(destPath);
        if (!dir.exists() && !dir.isDirectory()) {
            dir.mkdirs();
        }

        File file = new File(destPath + "/" + fileName);

        try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
             ByteArrayOutputStream baos = new ByteArrayOutputStream(Base64.getDecoder().decode(base64).length)) {

            baos.write(Base64.getDecoder().decode(base64));
            baos.writeTo(bos);

        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

        return true;
    }

    /**
     * @return String
     * @description 将文件转base64字符串
     * @date 2018年3月20日
     * @author changyl
     * File转成编码成BASE64
     */

    public static String fileToBase64(String path) {
        String base64 = null;
        try (InputStream in = new FileInputStream(new File(path));) {
            byte[] bytes = new byte[(int) new File(path).length()];
            in.read(bytes);
            base64 = Base64.getEncoder().encodeToString(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return base64;
    }

    public static String fileToBase64(MultipartFile multipartFile) {
        String base64 = null;
        try {
            base64 = Base64.getEncoder().encodeToString(multipartFile.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return base64;
    }

    /**
     * 是否是图片附件
     */
    public static boolean isImage(String filename) {
        if (filename == null || filename.trim().isEmpty()) {
            return false;
        }
        return ArrayUtils.contains(IMAGES_SUFFIXES, FilenameUtils.getExtension(filename).toLowerCase());
    }

    public static void main(String[] args) {
//        String dirName = "E:/createFile/";// 创建目录
//        FileUtils.mkDir(dirName);// 调用方法创建目录
//        String fileName = dirName + "/file1.txt";// 创建文件
//        FileUtils.createFile(fileName);// 调用方法创建文件
//        String prefix = "temp";// 创建临时文件
//        String surfix = ".txt";// 后缀
//        for (int i = 0; i < 10; i++) {// 循环创建多个文件
//            System.out.println("创建临时文件: "// 调用方法创建临时文件
//                    + FileUtils.createTempFile(prefix, surfix, dirName));
//        }
        FileUtils.del("C:\\Users\\dothe\\Desktop\\源代码\\wind.zip");
    }


}
